package models

import (
	_ "fmt"
	"gitchina/kly_service/data"
	"gitchina/kly_service/errors"
	"gitchina/kly_service/util"
	"github.com/astaxie/beego"
	"github.com/pborman/uuid"
	"time"
)

var safemap = util.NewSafeMap()

type Auth struct{}

type Session struct {
	Expire     int64
	MemberInfo MemberRS
}

type LoginRQ struct {
	Phone      string `json:"phone"`
	Passwd     string `json:"password"`
	Platform   string `json:"platform"`
	RegisterId string `json:"register_id"`
}

func (a Auth) Login(phone, passwd, registerId, platform string) (mbrInfo MemberRS, err error) {
	var mbrDto data.MemberDto
	var r data.MemberRepo
	if mbrDto, err = r.CheckPhoneAndPasswd(phone, passwd); err == nil {
		var mbrId ID
		mbrId.Encode(ID_Shard, ID_Ver, ID_Member_Category, int64(mbrDto.Id))
		mbrInfo = MemberRS{
			Id:           mbrId,
			RawId:        mbrDto.Id,
			Name:         mbrDto.Name,
			NickName:     mbrDto.NickName,
			Phone:        mbrDto.Phone,
			MemberType:   mbrDto.TypeId,
			State:        mbrDto.State,
			Level:        mbrDto.Level,
			AuthLevel:    mbrDto.AuthLevel,
			IDCardNo:     mbrDto.IDCardNo,
			QRCodeUrl:    mbrDto.QRCode,
			PhotoUrl:     mbrDto.PhotoUrl,
			Token:        uuid.New(),
			QRCodeExists: len(mbrDto.QRCode) > 0,
		}

		a.ensureOneLogin(mbrInfo.Phone)
		safemap.Set(mbrInfo.Token, &Session{
			MemberInfo: mbrInfo,
			Expire:     time.Now().Add(time.Hour * time.Duration(beego.AppConfig.DefaultInt("tokenExpire", 72))).Unix(),
		})
		r.AddLoginLog(mbrInfo.RawId, 1, registerId, platform)
	} else {
		util.GetLogger().Error("[model] - login error: %s", err.Error())
		err = errors.New(errors.MSG_Mbr_Invalid_Pwd_Or_Phone)
	}

	return
}

func (a Auth) Authenticate(token string) (pass bool, mbrId string) {
	if val, ok := safemap.Get(token); ok {
		session := val.(*Session)
		if time.Now().Unix() < session.Expire {
			pass = true
			mbrId = string(session.MemberInfo.Id)
			session.Expire = time.Now().Add(time.Hour * time.Duration(beego.AppConfig.DefaultInt("tokenExpire", 72))).Unix()
			safemap.Set(token, session)
		} else {
			a.Logout(token)
		}
	}
	return
}

func (a Auth) Logout(token string) {
	if val, ok := safemap.Get(token); ok {
		session := val.(*Session)
		if _, _, _, id, err := session.MemberInfo.Id.Decode(); err == nil {
			var r data.MemberRepo
			r.AddLoginLog(int(id), 2, "", "")
		}
		safemap.Remove(token)

	}
}

//not good
func (a Auth) ensureOneLogin(phone string) {
	var token string
	for _, kvp := range safemap.IterAll() {
		key := kvp.Key.(string)
		val := kvp.Value.(*Session)
		if val.MemberInfo.Phone == phone {
			token = key
			break
		}
	}
	if token != "" {
		safemap.Remove(token)
	}
}
